package com.unswift.utils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;

import com.unswift.annotation.api.Api;
import com.unswift.annotation.api.ApiField;
import com.unswift.annotation.api.ApiMethod;

@Api(value="日期公共操作类", author="unswift", date="2022-12-16", version="1.0.0")
public final class DateUtils {
	
	@ApiField("日期本地线程对象（每个线程只创建一个格式化对象）")
	private static ThreadLocal<SimpleDateFormat> formatLocal=new InheritableThreadLocal<SimpleDateFormat>(){
		protected SimpleDateFormat initialValue() {//初始化本线程变量
			return new SimpleDateFormat();
		};
	};
	
	@ApiMethod(value="将日期对象转换为指定格式的字符串", params={@ApiField("日期对象"), @ApiField("转换的格式")}, returns=@ApiField("返回日期字符串"))
	public static String format(Date date, String format){
		SimpleDateFormat simpleFormat=formatLocal.get();
		simpleFormat.applyPattern(format);
		return simpleFormat.format(date);
	}
	
	@ApiMethod(value="格式化当前时间", params=@ApiField("转换的格式"), returns=@ApiField("返回日期字符串"))
	public static String format(String format){
		return format(new Date(), format);
	}
	
	@ApiMethod(value="解析日期字符串", params={@ApiField("日期字符串"),@ApiField("日期字符串格式")}, returns=@ApiField("日期对象"))
	public static Date parse(String date, String format){
		if(ObjectUtils.isEmpty(date)) {
			return null;
		}
		SimpleDateFormat simpleFormat=formatLocal.get();
		simpleFormat.applyPattern(format);
		try {
			return simpleFormat.parse(date);
		} catch (Exception e) {
			e.printStackTrace();
			throw ExceptionUtils.exception("date.parse.exception", e, date, format, e.getMessage());
		}
	}
	
	@ApiMethod(value="日期字符串自动转日期", params={@ApiField("日期字符串")})
	public static Date parse(String date){
		if(ObjectUtils.isEmpty(date)){
			return null;
		}
		String[] dates;
		if(date.contains(" ")){
			dates=date.split(" ");
		}else{
			dates=new String[]{date};
		}
		StringBuilder format=new StringBuilder();
		String[] array, childArray;
		int i=0;
		for (String item : dates) {
			if(i>0){
				format.append(" ");
			}
			if(item.contains("-")){
				array=item.split("\\-");
				if(array.length!=3){
					throw ExceptionUtils.message("date.format.not.implemented", item);
				}
				if(array[0].length()==4){
					format.append("yyyy-");
				}else if(array[0].length()==2){
					format.append("yy-");
				}else{
					throw ExceptionUtils.message("date.format.not.implemented", item);
				}
				if(array[1].length()==2){
					format.append("MM-");
				}else if(array[1].length()==1){
					format.append("M-");
				}else{
					throw ExceptionUtils.message("date.format.not.implemented", item);
				}
				if(array[2].length()==2){
					format.append("dd");
				}else if(array[2].length()==1){
					format.append("d");
				}else{
					throw ExceptionUtils.message("date.format.not.implemented", item);
				}
			}else if(item.contains(":")){
				array=item.split("\\:");
				if(array.length>3){
					throw ExceptionUtils.message("date.format.not.implemented", item);
				}
				if(array[0].length()==2){
					format.append("HH:");
				}else if(array[0].length()==1){
					format.append("H.");
				}else{
					throw ExceptionUtils.message("date.format.not.implemented", item);
				}
				if(array.length==1){
					continue;
				}
				if(array[1].length()==2){
					format.append("mm:");
				}else if(array[1].length()==1){
					format.append("m.");
				}else{
					throw ExceptionUtils.message("date.format.not.implemented", item);
				}
				if(array.length==2){
					continue;
				}
				if(array[2].contains(".")){
					childArray=array[2].split("\\.");
					if(childArray.length!=2){
						throw ExceptionUtils.message("date.format.not.implemented", array[2]);
					}
					if(childArray[0].length()==2){
						format.append("ss.");
					}else if(childArray[0].length()==1){
						format.append("s.");
					}else{
						throw ExceptionUtils.message("date.format.not.implemented", item);
					}
					if(childArray[1].length()==6){
						format.append("SSSSSS");
					}else if(childArray[1].length()==3){
						format.append("SSS");
					}else{
						format.append("S");
					}
				}else{
					if(array[2].length()==2){
						format.append("ss");
					}else if(array[2].length()==1){
						format.append("s.");
					}else{
						throw ExceptionUtils.message("date.format.not.implemented", item);
					}
				}
			}else{
				throw ExceptionUtils.message("date.format.not.implemented", item);
			}
			i++;
		}
		return parse(date, format.toString());
	}
	
	@ApiMethod(value="将LocalDateTime对象转为Date对象", params=@ApiField("LocalDateTime对象"), returns=@ApiField("Date对象"))
	public static Date localDateTimeToDate(LocalDateTime localDateTime){
		ZoneId zoneId = ZoneId.systemDefault();
		ZonedDateTime zonedDateTime =localDateTime.atZone(zoneId);
		Instant instant = zonedDateTime.toInstant();
		return Date.from(instant);
	}
	
	@ApiMethod(value="将毫秒数变为秒", params={@ApiField("毫秒数"), @ApiField("精度")}, returns=@ApiField("秒数"))
	public static BigDecimal millisToSecond(long millis, int scale){
		return new BigDecimal(millis*1.0/1000.0).setScale(scale, RoundingMode.HALF_UP);
	}
	
	@ApiMethod(value="获取差异（减少）日期", params = {@ApiField("初始日期"), @ApiField("差异值"), @ApiField("差异单位，yy：年份，MM：月份，dd：天，HH：时，mm：分，ss：秒，区分大小写")}, returns = @ApiField("差异日期"))
	public static Date getDiffSubDate(Date date, int difference, String unit) {
		difference=0-difference;
		Calendar calendar=Calendar.getInstance();
		calendar.setTime(date);
		if("yyyy".equals(unit)) {
			calendar.add(Calendar.YEAR, difference);
		}else if("MM".equals(unit)) {
			calendar.add(Calendar.MONTH, difference);
		}else if("dd".equals(unit)) {
			calendar.add(Calendar.DATE, difference);
		}else if("HH".equals(unit)) {
			calendar.add(Calendar.HOUR_OF_DAY, difference);
		}else if("mm".equals(unit)) {
			calendar.add(Calendar.MINUTE, difference);
		}else if("ss".equals(unit)) {
			calendar.add(Calendar.SECOND, difference);
		}else if("SSS".equals(unit)) {
			calendar.add(Calendar.MILLISECOND, difference);
		}
		return calendar.getTime();
	}
	
	@ApiMethod(value="获取差异（减少）日期", params = {@ApiField("差异值"), @ApiField("差异单位，yy：年份，MM：月份，dd：天，HH：时，mm：分，ss：秒，区分大小写")}, returns = @ApiField("差异日期"))
	public static Date getDiffSubDate(int difference, String unit) {
		difference=0-difference;
		Calendar calendar=Calendar.getInstance();
		if("yyyy".equals(unit)) {
			calendar.add(Calendar.YEAR, difference);
		}else if("MM".equals(unit)) {
			calendar.add(Calendar.MONTH, difference);
		}else if("dd".equals(unit)) {
			calendar.add(Calendar.DATE, difference);
		}else if("HH".equals(unit)) {
			calendar.add(Calendar.HOUR_OF_DAY, difference);
		}else if("mm".equals(unit)) {
			calendar.add(Calendar.MINUTE, difference);
		}else if("ss".equals(unit)) {
			calendar.add(Calendar.SECOND, difference);
		}else if("SSS".equals(unit)) {
			calendar.add(Calendar.MILLISECOND, difference);
		}
		return calendar.getTime();
	}
	
	@ApiMethod(value="获取差异（增加）日期", params = {@ApiField("差异值"), @ApiField("差异单位，yy：年份，MM：月份，dd：天，HH：时，mm：分，ss：秒，区分大小写")}, returns = @ApiField("差异日期"))
	public static Date getDiffAddDate(int difference, String unit) {
		Calendar calendar=Calendar.getInstance();
		if("yyyy".equals(unit)) {
			calendar.add(Calendar.YEAR, difference);
		}else if("MM".equals(unit)) {
			calendar.add(Calendar.MONTH, difference);
		}else if("dd".equals(unit)) {
			calendar.add(Calendar.DATE, difference);
		}else if("HH".equals(unit)) {
			calendar.add(Calendar.HOUR_OF_DAY, difference);
		}else if("mm".equals(unit)) {
			calendar.add(Calendar.MINUTE, difference);
		}else if("ss".equals(unit)) {
			calendar.add(Calendar.SECOND, difference);
		}else if("SSS".equals(unit)) {
			calendar.add(Calendar.MILLISECOND, difference);
		}
		return calendar.getTime();
	}
	
	@ApiMethod(value="获取差异（增加）日期", params = {@ApiField("初始日期"), @ApiField("差异值"), @ApiField("差异单位，yy(yyyy)：年份，MM：月份，dd：天，HH：时，mm：分，ss：秒，区分大小写")}, returns = @ApiField("差异日期"))
	public static Date getDiffAddDate(Date date, int difference, String unit) {
		Calendar calendar=Calendar.getInstance();
		calendar.setTime(date);
		if("yyyy".equals(unit) || "yy".equals(unit)) {
			calendar.add(Calendar.YEAR, difference);
		}else if("MM".equals(unit)) {
			calendar.add(Calendar.MONTH, difference);
		}else if("dd".equals(unit)) {
			calendar.add(Calendar.DATE, difference);
		}else if("HH".equals(unit)) {
			calendar.add(Calendar.HOUR_OF_DAY, difference);
		}else if("mm".equals(unit)) {
			calendar.add(Calendar.MINUTE, difference);
		}else if("ss".equals(unit)) {
			calendar.add(Calendar.SECOND, difference);
		}else if("SSS".equals(unit)) {
			calendar.add(Calendar.MILLISECOND, difference);
		}
		return calendar.getTime();
	}
}
